package manager

import (
	"context"
	"errors"
	"quant/backend/api/dto"
	"quant/backend/conf"
	"quant/backend/db"

	"github.com/sirupsen/logrus"
	"xorm.io/xorm"
)

var (
	ErrRecordNotFound = errors.New("没有找到记录")
)

// BaseManager 基础服务泛型类
type BaseManager[T any] struct {
	engine    *xorm.Engine
	session   *xorm.Session
	tableName string
}

// NewBaseService 创建基础服务实例
func newManager[T any]() *BaseManager[T] {
	var model T
	tableName := getTableName(model, db.GetMySQL())
	return &BaseManager[T]{
		engine:    db.GetMySQL(),
		session:   nil,
		tableName: tableName,
	}
}

// 获取表名（支持自定义 TableName 方法）
func getTableName[T any](model T, engine *xorm.Engine) string {
	if tn, ok := any(model).(interface{ TableName() string }); ok {
		return tn.TableName()
	}
	return engine.TableName(model) // 使用 xorm 默认表名规则
}

// 基础CRUD操作
// --------------------------------------------------

// GetByID 根据ID获取记录
func (mgr *BaseManager[T]) GetByID(id any) (*T, error) {
	var result T
	has, err := mgr.engine.ID(id).Get(&result)
	if err != nil {
		return nil, err
	}
	if !has {
		return nil, ErrRecordNotFound
	}
	return &result, nil
}

// Create 创建记录
func (mgr *BaseManager[T]) Create(entity *T) (int64, error) {
	if mgr.session == nil {
		mgr.session = mgr.engine.NewSession()
		defer mgr.session.Close()
	}
	return mgr.session.Insert(entity)
}

// Update 更新记录
func (mgr *BaseManager[T]) Update(cols []string, id int64, entity *T) (int64, error) {
	if mgr.session == nil {
		mgr.session = mgr.engine.NewSession()
		defer mgr.session.Close()
	}

	if cols == nil {
		return mgr.session.ID(id).AllCols().Update(entity)
	} else {
		return mgr.session.ID(id).Cols(cols...).Update(entity)
	}
}

// DeleteById 删除记录
func (mgr *BaseManager[T]) DeleteById(id int64) error {
	if mgr.session == nil {
		mgr.session = mgr.engine.NewSession()
		defer mgr.session.Close()
	}
	affected, err := mgr.session.ID(id).Delete(new(T))
	if err != nil {
		return err
	}
	if affected == 0 {
		return ErrRecordNotFound
	}
	return nil
}

// Delete 删除记录
func (mgr *BaseManager[T]) Delete(entity *T) error {
	if mgr.session == nil {
		mgr.session = mgr.engine.NewSession()
		defer mgr.session.Close()
	}
	_, err := mgr.session.Delete(entity)
	if err != nil {
		return err
	}
	// if affected == 0 {
	// 	return ErrRecordNotFound
	// }
	return nil
}

func (mgr *BaseManager[T]) Truncate() error {
	// if mgr.session == nil {
	// 	mgr.session = mgr.engine.NewSession()
	// 	defer mgr.session.Close()
	// }
	tableName := getTableName(new(T), mgr.engine)
	_, err := mgr.engine.Exec("TRUNCATE TABLE " + tableName)
	if err != nil {
		return err
	}
	return nil
}

// FindWhere 查询记录（带分页和条件）
func (mgr *BaseManager[T]) FindWhere(query string, pageNo, pageSize int) ([]T, error) {
	var results []T
	mgr.session = mgr.engine.NewSession()
	defer mgr.session.Close()

	if len(query) <= 0 {
		mgr.session.Where(query)
	}

	if pageNo > 0 && pageSize > 0 {
		mgr.session.Limit(pageSize, (pageNo-1)*pageSize)
	}
	err := mgr.session.Find(&results)
	return results, err
}

// FindAll 查询所有记录
func (mgr *BaseManager[T]) FindAll() ([]T, error) {
	var results []T
	mgr.session = mgr.engine.NewSession()
	defer mgr.session.Close()

	err := mgr.session.Find(&results)
	logrus.Info("记录数：", len(results))
	return results, err
}

// WithTx 开启事务
func (mgr *BaseManager[T]) WithTx(ctx context.Context, fn func(*BaseManager[T]) (int64, error)) (int64, error) {
	mgr.session = mgr.engine.NewSession()
	defer func(session *xorm.Session) {
		err := session.Close()
		if err != nil {
			logrus.Error("事务回滚:", err)
		}
	}(mgr.session)

	var affected int64
	var err error

	if err = mgr.session.Begin(); err != nil {
		return 0, err
	}

	if affected, err = fn(mgr); err != nil {
		_ = mgr.session.Rollback()
		logrus.Error("事务回滚:", err)
		return 0, err
	}

	return affected, mgr.session.Commit()
}

// PagingQuery 通用分页查询方法
func (mgr *BaseManager[T]) PagingQuery(ctx context.Context, pageNo, pageSize int, queryFn func(*xorm.Session)) (*dto.PageResultDto[T], error) {
	mgr.session = mgr.engine.NewSession()
	defer mgr.session.Close()

	logrus.Info(ctx.Value("username"))

	// pageResult, err := mgr.initPage(int64(pageNo), int64(pageSize), queryFn)
	pageResult, err := mgr.initPage(int64(pageNo), int64(pageSize), queryFn)
	if err != nil {
		return nil, err
	}

	// 执行分页查询
	mgr.session.Limit(int(pageResult.PageSize), int((pageResult.PageNo-1)*pageResult.PageSize))
	if queryFn != nil {
		queryFn(mgr.session)
	}

	// 声明一个空切片, 注意,如果 list 为空时, 转 json,会变成 null
	// var list []T
	var list = make([]T, 0) // 声明和实例化（创建）一个空的切片
	if err := mgr.session.Find(&list); err != nil {
		return nil, err
	}
	pageResult.List = list
	return pageResult, nil
}

func (mgr *BaseManager[T]) initPage(pageNo, pageSize int64, queryFn func(*xorm.Session)) (*dto.PageResultDto[T], error) {
	if pageNo < 1 {
		pageNo = conf.Config.App.PageNo
	}
	if pageSize < 1 {
		pageSize = conf.Config.App.PageSize
	}
	// 创建新会话避免污染
	countSession := mgr.engine.NewSession()
	defer countSession.Close()
	// 执行自定义查询条件
	if queryFn != nil {
		queryFn(countSession)
	}
	// 获取总数
	total, err := countSession.Count(new(T))
	if err != nil {
		return nil, err
	}
	var pageCount int64 = 0
	if total%pageSize == 0 {
		pageCount = total / pageSize
	} else {
		pageCount = total/pageSize + 1
	}
	pageResult := &dto.PageResultDto[T]{
		PageNo:    pageNo,
		PageSize:  pageSize,
		PageCount: pageCount,
		Total:     total,
	}
	return pageResult, nil
}
